package org.create.builder;

import org.apache.commons.lang3.ArrayUtils;
import org.create.bean.Constants;
import org.create.bean.FieldInfo;
import org.create.bean.TableInfo;
import org.create.utils.DataTool;
import org.create.utils.DateTool;
import org.create.utils.IoTool;
import org.create.utils.LogTool;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import static org.create.bean.Constants.*;


public class BuildQuery {
    private static BufferedWriter bw;

    private static void buildPackageComment(TableInfo tableInfo) throws IOException {
        bw.write("package " + PACKAGE_BASE + "." + PACKAGE_QUERY + ";");
        appendLine(2);
        if (tableInfo.getHaveBigDecimal()) {
            bw.write("import java.math.BigDecimal;");
            appendLine();
        }
        if (tableInfo.getHaveDate() || tableInfo.getHaveDateTime()) {
            bw.write("import java.util.Date;");
            appendLine();
        }
        appendLine(2);
    }

    private static void buildDescriptionComment(TableInfo tableInfo) throws IOException {
        bw.write("/**");
        appendLine();
        bw.write(" * Description " + tableInfo.getComment());
        appendLine();
        bw.write(" * date " + DateTool.DateFormat(new Date(), YMD_HMS));
        appendLine();
        bw.write(" */");
        appendLine();
    }

    private static void buildClassComment(TableInfo tableInfo) throws IOException {
        bw.write("public class " + tableInfo.getBeanName() + "Query" + " {");
        appendLine();
        buildFieldComment(tableInfo.getFieldList());
        appendLine();
        buildMethodDescriptionComment(tableInfo.getFieldList());
        buildToString(tableInfo);
        bw.write("}");
    }

    private static void buildFieldComment(List<FieldInfo> fieldInfoList) throws IOException {
        for (FieldInfo fieldInfo : fieldInfoList) {
            buildFieldDescriptionComment(fieldInfo);
            bw.write("    private " + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + ";");
            appendLine();
            if (fieldInfo.getJavaType().equals("String")) {
                bw.write("    private " + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + QUERY_FUZZY + ";");
                appendLine();
            }
            if (fieldInfo.getJavaType().equals("Date")) {
                bw.write("    private " + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + QUERY_TIME_START + ";");
                appendLine();
                bw.write("    private " + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + QUERY_TIME_END + ";");
                appendLine();
            }
        }
        writer("    private Integer " + "pageSize;");
        writer("    private Integer " + "pageNo;");
        writer("    private Integer " + "pageTotalCount;");
        writer("    private String order;");
        writer("    private SimplePage simplePage;");
    }

    private static void buildFieldDescriptionComment(FieldInfo fieldInfo) throws IOException {
        bw.write("    /**");
        appendLine();
        bw.write("     * " + fieldInfo.getComment());
        appendLine();
        bw.write("     */");
        appendLine();
    }

    private static void buildMethodDescriptionComment(List<FieldInfo> fieldInfoList) throws IOException {
        for (FieldInfo fieldInfo : fieldInfoList) {
            bw.write("    public " + fieldInfo.getJavaType() + " get");
            bw.write(fieldInfo.getPropertyName().substring(0, 1).toUpperCase());
            bw.write(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "");
            bw.write("() {");
            appendLine();
            bw.write("        return " + fieldInfo.getPropertyName() + ";");
            appendLine();
            bw.write("    }");
            appendLine(2);
            bw.write("    public void set");
            bw.write(fieldInfo.getPropertyName().substring(0, 1).toUpperCase());
            bw.write(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "");
            bw.write("(" + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + ") {");
            appendLine();
            bw.write("        this." + fieldInfo.getPropertyName() + " = " + fieldInfo.getPropertyName() + ";");
            appendLine();
            bw.write("    }");
            appendLine(2);
            if (fieldInfo.getJavaType().equals("String")) {
                bw.write("    public " + fieldInfo.getJavaType() + " get");
                bw.write(fieldInfo.getPropertyName().substring(0, 1).toUpperCase());
                bw.write(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "");
                bw.write(QUERY_FUZZY);
                bw.write("() {");
                appendLine();
                bw.write("        return " + fieldInfo.getPropertyName() + QUERY_FUZZY + ";");
                appendLine();
                bw.write("    }");
                appendLine(2);
                bw.write("    public void set");
                bw.write(fieldInfo.getPropertyName().substring(0, 1).toUpperCase());
                bw.write(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "");
                bw.write(QUERY_FUZZY);
                bw.write("(" + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + QUERY_FUZZY + ") {");
                appendLine();
                bw.write("        this." + fieldInfo.getPropertyName() + QUERY_FUZZY + " = " + fieldInfo.getPropertyName() + QUERY_FUZZY + ";");
                appendLine();
                bw.write("    }");
                appendLine(2);
            }
            if (fieldInfo.getJavaType().equals("Date")) {
                bw.write("    public " + fieldInfo.getJavaType() + " get");
                bw.write(fieldInfo.getPropertyName().substring(0, 1).toUpperCase());
                bw.write(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "");
                bw.write(QUERY_TIME_START);
                bw.write("() {");
                appendLine();
                bw.write("        return " + fieldInfo.getPropertyName() + QUERY_TIME_START + ";");
                appendLine();
                bw.write("    }");
                appendLine(2);
                bw.write("    public void set");
                bw.write(fieldInfo.getPropertyName().substring(0, 1).toUpperCase());
                bw.write(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "");
                bw.write(QUERY_TIME_START);
                bw.write("(" + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + QUERY_TIME_START + ") {");
                appendLine();
                bw.write("        this." + fieldInfo.getPropertyName() + QUERY_TIME_START + " = " + fieldInfo.getPropertyName() + QUERY_TIME_START + ";");
                appendLine();
                bw.write("    }");
                appendLine(2);
                //---------------------------------------------------------------
                bw.write("    public " + fieldInfo.getJavaType() + " get");
                bw.write(fieldInfo.getPropertyName().substring(0, 1).toUpperCase());
                bw.write(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "");
                bw.write(QUERY_TIME_END);
                writer("() {");
                writer("        return " + fieldInfo.getPropertyName() + QUERY_TIME_END + ";");
                writer("    }", 2);
                writer("    public void set", 0);
                writer(fieldInfo.getPropertyName().substring(0, 1).toUpperCase(), 0);
                writer(fieldInfo.getPropertyName().length() > 1 ? fieldInfo.getPropertyName().substring(1) : "", 0);
                writer(QUERY_TIME_END, 0);
                writer("(" + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + QUERY_TIME_END + ") {");
                writer("        this." + fieldInfo.getPropertyName() + QUERY_TIME_END + " = " + fieldInfo.getPropertyName() + QUERY_TIME_END + ";");
                writer("    }", 2);
            }
        }
        writer("    public Integer getPageSize() {");
        writer("        return pageSize;");
        writer("    }", 2);
        writer("    public void setPageSize(Integer pageSize) {");
        writer("        this.pageSize = pageSize;");
        writer("    }", 2);
        writer("    public Integer getPageNo() {");
        writer("        return pageNo;");
        writer("    }", 2);
        writer("    public void setPageNo(Integer pageNo) {");
        writer("        this.pageNo = pageNo;");
        writer("    }", 2);
        writer("    public Integer getPageTotalCount() {");
        writer("        return pageTotalCount;");
        writer("    }", 2);
        writer("    public void setPageTotalCount(Integer pageTotalCount) {");
        writer("        this.pageTotalCount = pageTotalCount;");
        writer("    }", 2);
        writer("    public String getOrder() {");
        writer("        return order;");
        writer("    }", 2);
        writer("    public void setOrder(String order) {");
        writer("        this.order = order;");
        writer("    }", 2);
        writer("    public SimplePage getSimplePage() {");
        writer("        return simplePage;");
        writer("    }", 2);
        writer("    public void setSimplePage(SimplePage simplePage) {");
        writer("        this.simplePage = simplePage;");
        writer("    }", 2);
    }

    public static void buildToString(TableInfo tableInfo) throws IOException {
        boolean firstLoop = true;
        writer("    @Override");
        writer("    public String toString() {");
        writer("        return \"" + tableInfo.getBeanName() + "{\" +");
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if (firstLoop) {
                writer("                \"" + fieldInfo.getPropertyName() + "=\" + " + fieldInfo.getPropertyName() + " +");
                firstLoop = false;
            } else {
                writer("                \", " + fieldInfo.getPropertyName() + "=\" + " + fieldInfo.getPropertyName() + " +");
            }
            if (fieldInfo.getJavaType().equals("String")) {
                writer("                \", " + fieldInfo.getPropertyName() + QUERY_FUZZY + "=\" + " + fieldInfo.getPropertyName() + QUERY_FUZZY + " +");
            }
            if (fieldInfo.getJavaType().equals("Date")) {
                writer("                \", " + fieldInfo.getPropertyName() + QUERY_TIME_START + "=\" + " + fieldInfo.getPropertyName() + QUERY_TIME_START + " +");
                writer("                \", " + fieldInfo.getPropertyName() + QUERY_TIME_END + "=\" + " + fieldInfo.getPropertyName() + QUERY_TIME_END + " +");
            }
        }
        writer("                '}';");
        writer("    }");
    }

    private static void writer(String str) throws IOException {
        writer(str, 1);
    }

    private static void writer(String str, int num) throws IOException {
        bw.write(str);
        if (num > 0) {
            appendLine(num);
        }
    }

    private static void appendLine() throws IOException {
        appendLine(1);
    }

    private static void appendLine(int loop) throws IOException {
        if (loop == 1) {
            bw.newLine();
        } else {
            for (int i = 0; i < loop; i++) {
                bw.newLine();
            }
        }
    }

    public static void run(List<TableInfo> tableInfoList) {
        for (TableInfo tableInfo : tableInfoList) {
            File file = new File(PATH_QUERY + tableInfo.getBeanName() + "Query" + JAVA_SUFFIX);
            File dir = file.getParentFile();
            boolean d = dir.mkdirs();
            LogTool.printLog(d, "新建目录", dir);
            try {
                boolean r = file.createNewFile();
                LogTool.printLog(r, "新建文件", file);
                bw = IoTool.createBw(file);
                buildPackageComment(tableInfo);
                buildDescriptionComment(tableInfo);
                buildClassComment(tableInfo);
            } catch (Exception e) {
                LogTool.printError(e);
            } finally {
                IoTool.close();
            }
        }
    }
}
